﻿// -----------------------------------------------------------------------
// <copyright file="TransactionsTests.cs">
// Copyright (c) 2012-2013 Andrey Veselov. All rights reserved.
// License:  Microsoft Public License (MS-PL)
// Contacts: http://andrey.moveax.com  andrey@moveax.com
// </copyright>
// -----------------------------------------------------------------------

namespace Moveax.DataAccess.Cqrs.Highway.EF.UnitTests
{
	using Microsoft.VisualStudio.TestTools.UnitTesting;
	using Moveax.DataAccess.Cqrs.Highway.EF.UnitTests.DataAccess.Database.Dto;
	using Moveax.DataAccess.Cqrs.Highway.UnitTests.Model.Queries;

	[TestClass]
	public class TransactionsTests : TestClassBase
	{
		[TestMethod]
		public void EFTransactionCommit()
		{
			// Arrange 
			int objectCountAtBegin = 0;
			int objectCountAtInnerEnd = 0;
			int objectCountAtEnd = 0;
			const int objectToInsert = 15;

			// Act
			using (var unitOfWork = this._unitOfWorkFactory.Create(enableTransactions: true)) {
				objectCountAtBegin = unitOfWork.ResolveQuery<IGetCountQuery>().Execute<UserDto>();

				this.InsertObjectsIntoRepository(unitOfWork, objectToInsert);

				using (var innerUnitOfWork = unitOfWork.BeginTransaction()) {
					this.InsertObjectsIntoRepository(innerUnitOfWork, objectToInsert);
					innerUnitOfWork.Commit();
				}

				objectCountAtInnerEnd = unitOfWork.ResolveQuery<IGetCountQuery>().Execute<UserDto>();

				unitOfWork.Commit();
			}

			objectCountAtEnd = this._unitOfWorkFactory.ExecuteSingleQuery<IGetCountQuery, int>(q => q.Execute<UserDto>());

			// Assert
			Assert.AreEqual(objectCountAtBegin + objectToInsert, objectCountAtInnerEnd);
			Assert.AreEqual(objectCountAtBegin + objectToInsert * 2, objectCountAtEnd);
		}

		[TestMethod]
		public void EFTransactionCommitWithRollback()
		{
			// Arrange 
			int objectCountAtBegin = 0;
			int objectCountAtInnerEnd = 0;
			int objectCountAtEnd = 0;
			const int objectToInsert = 15;

			// Act
			using (var unitOfWork = this._unitOfWorkFactory.Create(enableTransactions: true)) {
				objectCountAtBegin = unitOfWork.ResolveQuery<IGetCountQuery>().Execute<UserDto>();

				this.InsertObjectsIntoRepository(unitOfWork, objectToInsert);

				using (var innerUnitOfWork = unitOfWork.BeginTransaction()) {
					this.InsertObjectsIntoRepository(innerUnitOfWork, objectToInsert);
					innerUnitOfWork.Commit();
				}

				objectCountAtInnerEnd = unitOfWork.ResolveQuery<IGetCountQuery>().Execute<UserDto>();

				unitOfWork.Rollback();
			}

			objectCountAtEnd = this._unitOfWorkFactory.ExecuteSingleQuery<IGetCountQuery, int>(q => q.Execute<UserDto>());

			// Assert
			Assert.AreEqual(objectCountAtBegin + objectToInsert, objectCountAtInnerEnd);
			Assert.AreEqual(objectCountAtBegin, objectCountAtEnd);
		}

		[TestMethod]
		public void EFTransactionRollbackWithCommit()
		{
			// Arrange 
			int objectCountAtBegin = 0;
			int objectCountAtInnerEnd = 0;
			int objectCountAtEnd = 0;
			const int objectToInsert = 15;

			// Act
			using (var unitOfWork = this._unitOfWorkFactory.Create(enableTransactions: true)) {
				objectCountAtBegin = unitOfWork.ResolveQuery<IGetCountQuery>().Execute<UserDto>();

				this.InsertObjectsIntoRepository(unitOfWork, objectToInsert);

				using (var innerUnitOfWork = unitOfWork.BeginTransaction()) {
					this.InsertObjectsIntoRepository(innerUnitOfWork, objectToInsert);
					innerUnitOfWork.Rollback();
				}

				objectCountAtInnerEnd = unitOfWork.ResolveQuery<IGetCountQuery>().Execute<UserDto>();

				unitOfWork.Commit();
			}

			objectCountAtEnd =
				this._unitOfWorkFactory.ExecuteSingleQuery<IGetCountQuery, int>(q => q.Execute<UserDto>());

			// Assert
			Assert.AreEqual(objectCountAtBegin, objectCountAtInnerEnd);
			Assert.AreEqual(objectCountAtBegin + objectToInsert, objectCountAtEnd);
		}

		[TestMethod]
		public void EFTransactionRollback()
		{
			// Arrange 
			int objectCountAtBegin = 0;
			int objectCountAtInnerEnd = 0;
			int objectCountAtEnd = 0;
			const int objectToInsert = 15;

			// Act
			using (var unitOfWork = this._unitOfWorkFactory.Create(enableTransactions: true)) {
				objectCountAtBegin = unitOfWork.ResolveQuery<IGetCountQuery>().Execute<UserDto>();

				this.InsertObjectsIntoRepository(unitOfWork, objectToInsert);

				using (var innerUnitOfWork = unitOfWork.BeginTransaction()) {
					this.InsertObjectsIntoRepository(innerUnitOfWork, objectToInsert);
					innerUnitOfWork.Rollback();
				}

				objectCountAtInnerEnd = unitOfWork.ResolveQuery<IGetCountQuery>().Execute<UserDto>();

				unitOfWork.Rollback();
			}

			objectCountAtEnd = this._unitOfWorkFactory.ExecuteSingleQuery<IGetCountQuery, int>(q => q.Execute<UserDto>());

			// Assert
			Assert.AreEqual(objectCountAtBegin, objectCountAtInnerEnd);
			Assert.AreEqual(objectCountAtBegin, objectCountAtEnd);
		}
	}
}